package com.jzo2o.health.listener;

import com.jzo2o.api.trade.TradingApi;
import com.jzo2o.api.trade.dto.response.TradingResDTO;
import com.jzo2o.api.trade.enums.TradingStateEnum;
import com.jzo2o.common.constants.UserType;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.model.msg.TradeStatusMsg;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.JsonUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.constant.HealthMqConstants;
import com.jzo2o.health.constant.TradeConstants;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.model.OrderUpdateStatusDTO;
import com.jzo2o.health.model.domain.Orders;
import com.jzo2o.health.model.domain.OrdersCancelled;
import com.jzo2o.health.service.IOrderCancelService;
import com.jzo2o.health.service.IOrderCommonService;
import com.jzo2o.health.service.IOrderCreateService;
import com.jzo2o.health.service.IReservationSettingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 监听MQ消息
 * @author itcast
 **/
@Slf4j
@Component
public class OrderStatusListener {
    @Resource
    private IOrderCommonService orderCommonService;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private IOrderCancelService orderCancelService;
    @Resource
    private IReservationSettingService reservationSettingService;
    @Resource
    private TradingApi tradingApi;

    /**
     * 接收支付成功信息
     * @param msg 消息
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = TradeConstants.MQ_TRADE_QUEUE),
            exchange = @Exchange(name = HealthMqConstants.Exchanges.TRADE, type = ExchangeTypes.TOPIC),
            key = HealthMqConstants.RoutingKeys.TRADE_UPDATE_STATUS))
    public void listenTradeUpdatePayStatusMsg(String msg) {
        log.info("接收到支付结果状态的消息 ({})-> {}", HealthMqConstants.Queues.ORDERS_TRADE_UPDATE_STATUS, msg);

        List<TradeStatusMsg> msgList = JsonUtils.parseArray(msg).toList(TradeStatusMsg.class);
        if (CollUtils.isEmpty(msgList)) {
            return;
        }

        // 处理当前微服务并且支付成功的订单
        List<TradeStatusMsg> tradeStatusMsgList = msgList.stream()
                .filter(statusMsg -> IOrderCreateService.PRODUCT_APP_ID.equals(statusMsg.getProductAppId())
                        && TradingStateEnum.YJS.getCode().equals(statusMsg.getStatusCode()))
                .collect(Collectors.toList());

        transactionTemplate.executeWithoutResult(status -> {
            for (TradeStatusMsg tradeStatusMsg : tradeStatusMsgList) {
                if (!orderCommonService.updateStatus(OrderUpdateStatusDTO.builder()
                        .id(tradeStatusMsg.getProductOrderNo())
                        .originStatus(OrderStatusEnum.NO_PAY)
                        .targetStatus(OrderStatusEnum.WAITING_CHECKUP)
                        .payStatus(OrderPayStatusEnum.PAY_SUCCESS)
                        .tradingOrderNo(tradeStatusMsg.getTradingOrderNo())
                        .transactionId(tradeStatusMsg.getTransactionId())
                        .tradingChannel(tradeStatusMsg.getTradingChannel())
                        .payTime(LocalDateTime.now()).build())) {
                    throw new DBException("更新订单状态失败");
                }
            }
        });
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = HealthMqConstants.Queues.DELAY_OUT),
            exchange = @Exchange(name = HealthMqConstants.Exchanges.HEALTH_ORDER, type = ExchangeTypes.TOPIC),
            key = HealthMqConstants.RoutingKeys.ORDER_OVERTIME_OUT))
    public void handleOverTimeOrder(String msg) {
        Long orderId = Long.parseLong(msg);
        if (ObjectUtils.isEmpty(orderId)) {
            return;
        }

        Orders order = orderCommonService.getById(orderId);
        if (ObjectUtils.isEmpty(order)) {
            return;
        }

        if (order.getOrderStatus() == OrderStatusEnum.NO_PAY && order.getPayStatus() == OrderPayStatusEnum.NO_PAY) {
            Long tradingOrderNo = order.getTradingOrderNo();
            if (ObjectUtils.isNotEmpty(tradingOrderNo)) {
                // 再次请求防止已支付
                TradingResDTO tradingResDTO = tradingApi.findTradResultByTradingOrderNo(tradingOrderNo);
                if (ObjectUtils.isNotEmpty(tradingResDTO) && tradingResDTO.getTradingState() == TradingStateEnum.YJS) {
                    return;
                }
            }

            // 事务更新数据表(取消订单)
            transactionTemplate.executeWithoutResult(status -> {
                orderCancelService.cancelOrder(OrdersCancelled.builder()
                        .id(orderId)
                        .cancelTime(LocalDateTime.now())
                        .cancelReason("订单超时自动取消")
                        .cancellerType(UserType.SYSTEM)
                        .build());

                // 已预约人数 - 1
                reservationSettingService.plusReservationCount(order.getReservationDate(), -1);
            });
        }
    }
}